package com.cea.papyrus.ocl.validator.actions;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.emf.validation.examples.general.ValidationPlugin;
import org.eclipse.emf.validation.examples.general.constraints.ValidationDelegateClientSelector2;
import org.eclipse.emf.validation.examples.general.internal.l10n.ValidationMessages;
import org.eclipse.emf.validation.marker.MarkerUtil;
import org.eclipse.emf.validation.model.EvaluationMode;
import org.eclipse.emf.validation.model.IConstraintStatus;
import org.eclipse.emf.validation.service.IBatchValidator;
import org.eclipse.emf.validation.service.ModelValidationService;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IActionDelegate;
import org.eclipse.ui.IEditorActionDelegate;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IViewActionDelegate;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.dialogs.ElementTreeSelectionDialog;
import org.eclipse.ui.dialogs.ListDialog;
import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
import org.eclipse.uml2.uml.Element;

import com.cea.papyrus.core.editor.MultiDiagramEditor;
import com.cea.papyrus.core.editpart.IUMLElementEditPart;
import com.cea.papyrus.core.treeeditpart.TreeOutlinePage;
/**
 * This class is used to launch the OCL validator,
 * It displays error and put in red target element in the outline
 * This code was udapted from {@link BatchValidationDelegate}
 * @author PT202707
 *
 */
public class ProfileConstraintValidation implements IViewActionDelegate, IActionDelegate, IEditorActionDelegate {

	private ArrayList<Element> selectedElements=null;
	private Shell shell=null;
	private String title="";
	private IEditorPart editor;

	
	/**
	 * Constructor for ProfileConstraintValidation
	 */
	public ProfileConstraintValidation() {
		super();

	}
	/**
	 * {@inheritDoc}
	 */
	public void init(IViewPart view){}
	/**
	 * {@inheritDoc}
	 */
	public void setActivePart(IAction action, IWorkbenchPart targetPart) {
		if(targetPart!=null){
			this.shell=targetPart.getSite().getShell();}
		this.title=targetPart.getTitle();
		this.editor=targetPart.getSite().getWorkbenchWindow().getActivePage().getActiveEditor();

	}

	/**
	 * {@inheritDoc}
	 */
	public void run(IAction action) {
		
		if(selectedElements.size()!=0){
			this.editor= PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getActiveEditor();
			ValidationDelegateClientSelector2.running = true;			
		
			//set element color in the outline to default
			if(editor instanceof MultiDiagramEditor){
				TreeOutlinePage outline= (TreeOutlinePage) ((MultiDiagramEditor)editor).getAdapter(IContentOutlinePage.class);			
				outline.setDefault();
			}
		
			//copied code from BatchValidationDelegate
			IBatchValidator validator = (IBatchValidator)ModelValidationService.getInstance()
			.newValidator(EvaluationMode.BATCH);
			validator.setIncludeLiveConstraints(true);
			final IStatus status = validator.validate(selectedElements);

			if (status.isOK()) {
				MessageDialog.openInformation(shell, title,
						ValidationMessages.BatchValidationDelegate_successMessage);
				return;
			} else {
				ElementTreeSelectionDialog dialog = new ElementTreeSelectionDialog(shell, new ErrorLabelProvider(), 
						new ErrorTreeContentProvider(status));
				dialog.setInput(status);
				dialog.setTitle(title);

				dialog.setBlockOnOpen(true);
				dialog.setMessage(ValidationMessages.BatchValidationDelegate_errorMessage);

				if (ListDialog.OK == dialog.open()) {
					Set errorSelections = new HashSet();
					if (!status.isMultiStatus()) {
						IConstraintStatus cstatus = (IConstraintStatus)status;
						errorSelections.add(cstatus.getTarget());
					} else {
						IStatus[] children = status.getChildren();
						for (int i = 0; i<children.length; i++) {
							IConstraintStatus cstatus = (IConstraintStatus)children[i];
							errorSelections.add(cstatus.getTarget());
						}
					}
					//****************************MODIFICATION*************************
					//display in red element that does not respect constraints
					if(editor instanceof MultiDiagramEditor){
						TreeOutlinePage outline= (TreeOutlinePage) ((MultiDiagramEditor)editor).getAdapter(IContentOutlinePage.class);			
						Object[] targetErrors=errorSelections.toArray();
						for(int i=0;i<targetErrors.length;i++){
							outline.markInRedElement((Element)targetErrors[i]);

						}
					}
				}
			}

			ValidationDelegateClientSelector2.running = false;

			// Create problem markers on the resources with validation failures/warnings.
			try {
				MarkerUtil.createMarkers(status);
			} catch (CoreException e) {
				ValidationPlugin.getDefault().getLog().log(e.getStatus());
			}
		}

	}


	/**
	 * {@inheritDoc}
	 */
	public void selectionChanged(IAction action, ISelection selection) {
		selectedElements=new ArrayList<Element>();
		action.setEnabled(false);
		//look for selected Element
		Iterator<Object> iter=((IStructuredSelection)selection).iterator();
		while(iter.hasNext()){
			Object e=iter.next();
			//this is element an elementlink to an UML element?
			if (e instanceof IUMLElementEditPart ){
				Element element = ((IUMLElementEditPart)e).getUmlElement();
				selectedElements.add(element);
				action.setEnabled(true);
			}
		}
	}

	public void setActiveEditor(IAction action, IEditorPart targetEditor) {
		this.editor=targetEditor;

	}
	/*****************************************************************************************
	 * 
	 * comes from IBM see {@link BatchValidationDelegate}
	 *
	 */
	private class ErrorLabelProvider extends LabelProvider {
		public String getText(Object element) {
			if (element instanceof IStatus) {
				return ((IStatus)element).getMessage();
			}
			return null;
		}
	}
	private class ErrorTreeContentProvider implements ITreeContentProvider {
		private IStatus status;
		ErrorTreeContentProvider(IStatus status){
			this.status=status;
		}
		public void dispose() {
		}

		public Object[] getElements(Object inputElement) {
			if (status != null && status.isMultiStatus() && status == inputElement) {
				return getChildren(inputElement);
			} else if (status != null && status == inputElement) {
				return new Object[] {status};
			}
			return new Object[0];
		}

		public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
			// Do nothing.
		}

		public Object[] getChildren(Object parentElement) {
			// TODO Auto-generated method stub					
			return ((IStatus) parentElement).getChildren();
		}

		public Object getParent(Object element) {
			// TODO Auto-generated method stub
			return status;
		}

		public boolean hasChildren(Object element) {					
			return (((IStatus) element).isMultiStatus());					
		}		
	}


}
